/*
 * 文件名：LuceneUtils.java	 
 * 时     间：下午12:41:13
 * 作     者：Administrator       
 * 版     权： 2012-2022 湖南智软网络科技, 公司保留所有权利.
 * 联     系：http://www.073586.com/
 */
package com.index.util;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.cz073586.tools.util.Log4jUtil;
import com.index.entity.Page;
import com.local.model.LocalCarInRepertory;
import com.local.page.CarInAndOutPageInfo;
import com.qianhai.common.utils.Tools;

/** 
 * 类描述:Lucene工具类(基于Lucene5.50封装)
 * @ClassName: IndexUtil 
 * @author lt
 * @date 2016年3月14日 下午12:41:13 
 */
public class LuceneUtils
{
    private static String INDEX_DIRA = "D:\\indexdataa";//保存路径a
    private static String INDEX_DIRB = "D:\\indexdatab";//保存路径b
    private static String FILENAME = "readme.txt";
    private static String WRITING = "writing";//正在写
    private static String WRITTEN = "written";//待写
    private static String READ = "read";//只读
	private static Analyzer analyzer = new IKAnalyzer();//中文分析器
	private static IndexWriter indexWriter;
	private static Log4jUtil log = Log4jUtil.getLog4j(LuceneUtils.class);
	
	/**
	 * 
	 * 方法描述：创建当前车牌号的索引
	 * @Title: createIndex 
	 * @param @param carNO 车牌号 carInUuid 进场id
	 * @param @return
	 * @return boolean 是否成功
	 * @user lt
	 * 2016年3月14日
	 * @throws
	 */
	public static boolean createIndex(String carNO,String carInUuid)
	{
		Date start = new Date();
		Directory directory = null;
	    try
		{   
	    	//打开文件
	    	directory = FSDirectory.open(Paths.get(INDEX_DIRA));
	    	
	    	//获取indexWriter
	        IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
	        indexWriter = new IndexWriter(directory, iwc);
	        
	        //索引生成
		    Document doc = new Document();
		    Field carInUuidField = new StringField("carInUuid", carInUuid, Field.Store.YES);
		    Field carNOField = new TextField("carNO", carNO, Field.Store.YES);
		    doc.add(carInUuidField);
		    doc.add(carNOField);
		    indexWriter.addDocument(doc);
		} 
	    catch (IOException e)
		{
			e.printStackTrace();
		}
	    finally
		{
	    	//关闭资源
	    	closeIndexWriter(indexWriter);
	    	closeDirectory(directory);
		}
	    Date end = new Date();
	    System.out.println("创建索引耗时：" + (end.getTime() - start.getTime()) + "ms\n");
		return true;
	}
	
	/**
	 * 
	 * 方法描述：批量创建当前车牌号的索引
	 * @Title: createIndex 
	 * @param @param carNO 车牌号 carInUuid 进场id
	 * @param @return
	 * @return boolean 是否成功
	 * @user lt
	 * 2016年3月14日
	 * @throws
	 */
	public static boolean batchCreateIndex(List<LocalCarInRepertory> list)
	{
		Date start = new Date();
		Directory directory = null;
		String indexPath = INDEX_DIRA;
	    try
		{
	    	//新建文件夹
	    	FileUtils.createFiles(INDEX_DIRA, INDEX_DIRB);
	    	
	    	//判断文件是否可写
	    	boolean flag = isWritten(indexPath);
	    	if(flag)
	    	{
	    		FileUtils.write(indexPath +"\\"+FILENAME,WRITING);
	    		FileUtils.write(INDEX_DIRB +"\\"+FILENAME,READ);
	    	}
	    	else
	    	{
	    		indexPath = INDEX_DIRB;
	    		FileUtils.write(indexPath +"\\"+FILENAME,WRITING);
	    		FileUtils.write(INDEX_DIRA +"\\"+FILENAME,READ);
	    	}
	    	
	    	List<Document> documents = new ArrayList<Document>();
	    	//打开文件
	    	directory = FSDirectory.open(Paths.get(indexPath));
	    	//放到内存中
	    	//directory = new RAMDirectory();
	    	
	    	//获取indexWriter
	        IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
	        indexWriter = new IndexWriter(directory, iwc);
	        
	        //写之前删除索引
	        deleteAllIndex(indexWriter);
	        
	        //批量生成索引
	        for(LocalCarInRepertory  carInRepertory: list)
	        {
	        	if(!Tools.isEmpty(carInRepertory.getCarNo()) && !Tools.isEmpty(carInRepertory.getCarInUuid())){
	        		Document doc = new Document();
	    		    Field carInUuidField = new StringField("carInUuid", carInRepertory.getCarInUuid(), Field.Store.YES);
	    		    Field carNOField = new TextField("carNO", carInRepertory.getCarNo(), Field.Store.YES);
	    		    
	    		    doc.add(carInUuidField);
	    		    doc.add(carNOField);
	    		    documents.add(doc);
				}
	        }
		    indexWriter.addDocuments(documents);
		} 
	    catch (IOException e)
		{
			e.printStackTrace();
		}
	    finally
		{
	    	//关闭资源
	    	closeIndexWriter(indexWriter);
	    	closeDirectory(directory);
	    	FileUtils.write(indexPath +"\\"+FILENAME,READ);
	    	if(INDEX_DIRA.equals(indexPath))
	    	{
	    		FileUtils.write(INDEX_DIRB +"\\"+FILENAME,WRITTEN);
	    	}
	    	else
	    	{
	    		FileUtils.write(INDEX_DIRA +"\\"+FILENAME,WRITTEN);
	    	}
		}
	    Date end = new Date();
	    if(log.isDebugEnabled())
		{
		  log.debug("->创建索引耗时："+ (end.getTime() - start.getTime()) + "ms\n");
		}
		return true;
	}
	
	/**
	 * 
	 * 方法描述：查询索引
	 * @Title: searchIndex 
	 * @param @param text
	 * @return void
	 * @user lt
	 * 2016年3月14日
	 * @throws
	 */
	public static List<String> searchIndex(String text)
	{
		Date start = new Date();
		IndexReader reader = null;
		Directory directory = null;
		List<String> uuidList = new ArrayList<String>();
		try
		{
			//判断读取目录路径
			String indexPath = INDEX_DIRA;
			boolean flag = isRead(indexPath);
			if(!flag)
			{
				indexPath = INDEX_DIRB;
			}
			
			directory = FSDirectory.open(Paths.get(indexPath));
			
			//获取IndexReader
			reader = DirectoryReader.open(directory);
		    IndexSearcher searcher = new IndexSearcher(reader);
		    
		    //查询车牌
		    QueryParser parser = new QueryParser("carNO", analyzer);
		    Query query = parser.parse(text);
		    TopDocs results = searcher.search(query, 200);
		    ScoreDoc[] hits = results.scoreDocs;
		    //System.out.println("总共匹配多少个：" + results.totalHits);
		    //迭代输出结果
		    for (int i = 0; i < hits.length; i++) {
		        Document hitDoc = searcher.doc(hits[i].doc);
		        //System.out.println("匹配得分：" + hits[i].score);
	            //System.out.println("文档索引ID：" + hits[i].doc);
		        //System.out.println(hitDoc.get("carNO"));
		        uuidList.add(hitDoc.get("carInUuid"));
		    }
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		} 
		catch (ParseException e)
		{
			e.printStackTrace();
		}
		finally
		{
			closeIndexReader(reader);
	    	closeDirectory(directory);
		}
		Date end = new Date();
        System.out.println("查询索引耗时：" + (end.getTime() - start.getTime()) + "ms\n");
        return uuidList;
	}
	
	
	/**
	 * 
	 * 方法描述：索引分页查询
	 * @Title: pageQueryIndex 
	 * @param @param carParkInPage
	 * @param @return
	 * @return Page<Document>
	 * @user Administrator
	 * 2016年3月22日
	 * @throws
	 */
	public static Page<Document> pageQueryIndex(CarInAndOutPageInfo<LocalCarInRepertory> carParkInPage)
	{
	    Date start = new Date();
		IndexReader reader = null;
		Directory directory = null;
		int pageSize = carParkInPage.getPageSize();
		int currentPage = carParkInPage.getCurrentPage();
		Page<Document> page = new Page<Document>(currentPage,pageSize);
		try
		{
			//判断读取目录路径
			String indexPath = INDEX_DIRA;
			boolean flag = isRead(indexPath);
			if(!flag)
			{
				indexPath = INDEX_DIRB;
			}
			
			directory = FSDirectory.open(Paths.get(indexPath));
			
			//获取IndexReader
			reader = DirectoryReader.open(directory);
		    IndexSearcher searcher = new IndexSearcher(reader);
		    
		    //查询车牌
		    QueryParser parser = new QueryParser("carNO", analyzer);
		    Query query = parser.parse(carParkInPage.getCarNo());
		    TopDocs results = searcher.search(query, carParkInPage.getPageSize());
		    ScoreDoc[] hits = results.scoreDocs;
		    
		    //查询起始记录位置
	        int begin = pageSize * (currentPage - 1);
	        //查询终止记录位置
	        int end = Math.min(begin + pageSize, hits.length);
	        
		    //迭代输出结果
	        List<String> carInUuidList = new ArrayList<String>();
		    for (int i=begin;i<end;i++) {
		        Document hitDoc = searcher.doc(hits[i].doc);
		        carInUuidList.add(hitDoc.get("carInUuid"));
		    }
		    page.setList(carInUuidList);
		    page.setTotalRecord(hits.length);
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		} 
		catch (ParseException e)
		{
			e.printStackTrace();
		}
		finally
		{
			closeIndexReader(reader);
	    	closeDirectory(directory);
		}
		Date end = new Date();
		if(log.isDebugEnabled())
		{
		  log.debug("->查询索引耗时："+ (end.getTime() - start.getTime()) + "ms\n");
		}
        return page;
	}
	
	
	/**
	 * @Title: searchTotalRecord
	 * @Description: 获取符合条件的总记录数
	 * @param query
	 * @return
	 * @throws IOException
	 */
	public static int searchTotalRecord(IndexSearcher search,Query query) {
		ScoreDoc[] docs = null;
		try {
			TopDocs topDocs = search.search(query, Integer.MAX_VALUE);
			if(topDocs == null || topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
				return 0;
			}
			docs = topDocs.scoreDocs;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return docs.length;
	}
	
	/**
	 * @Title: pageQuery
	 * @Description: Lucene分页查询
	 * @param searcher
	 * @param query
	 * @param page
	 * @throws IOException
	 */
	public static void pageQuery(IndexSearcher searcher,Directory directory,Query query,Page<Document> page) {
		int totalRecord = searchTotalRecord(searcher,query);
		//设置总记录数
		page.setTotalRecord(totalRecord);
		TopDocs topDocs = null;
		try {
			topDocs = searcher.searchAfter(page.getAfterDoc(),query, page.getPageSize());
		} catch (IOException e) {
			e.printStackTrace();
		}
		List<Document> docList = new ArrayList<Document>();
		ScoreDoc[] docs = topDocs.scoreDocs;
		int index = 0;
		for (ScoreDoc scoreDoc : docs) {
			int docID = scoreDoc.doc;
			Document document = null;
			try {
				document = searcher.doc(docID);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(index == docs.length - 1) {
				page.setAfterDoc(scoreDoc);
				page.setAfterDocId(docID);
			}
			docList.add(document);
			index++;
		}
		page.setItems(docList);
		closeIndexReader(searcher.getIndexReader());
	}
	
	/**
	 * 
	 * 方法描述：删除索引
	 * @Title: delete 
	 * @param @param str 删除的关键字
	 * @param @throws Exception
	 * @return void
	 * @user lt
	 * 2016年3月14日
	 * @throws
	 */
    public static void deleteIndex(String carInUuid) 
    {
        Date start = new Date();
        Directory directory = null;
        try
		{
			directory = FSDirectory.open(Paths.get(INDEX_DIRA));
			
			IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
	        indexWriter = new IndexWriter(directory, iwc);
	        
	        //精确删除索引
	        indexWriter.deleteDocuments(new Term("carInUuid",carInUuid));
		} 
        catch (IOException e)
		{
			e.printStackTrace();
		}
        finally
		{
	    	closeIndexWriter(indexWriter);
	    	closeDirectory(directory);
		}
        Date end = new Date();
        System.out.println("删除索引耗时：" + (end.getTime() - start.getTime()) + "ms\n");
    }
    
    /**
	 * 删除所有索引文档
	 * @param writer
	 */
	public static void deleteAllIndex(IndexWriter writer)
	{
		try
		{
			writer.deleteAll();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
    /**
     * 
     * 方法描述：关闭IndexReader
     * @Title: closeIndexReader 
     * @param @param reader
     * @return void
     * @user lt
     * 2016年3月17日
     * @throws
     */
	public static void closeIndexReader(IndexReader reader)
	{
		if (null != reader)
		{
			try 
			{
				reader.close();
				reader = null;
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 
	 * 方法描述：关闭IndexWriter
	 * @Title: closeIndexWriter 
	 * @param @param writer
	 * @return void
	 * @user lt
	 * 2016年3月17日
	 * @throws
	 */
	public static void closeIndexWriter(IndexWriter writer)
	{
		if(null != writer)
		{
			try
			{
				writer.close();
				writer = null;
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 
	 * 方法描述：关闭索引目录并销毁
	 * @Title: closeDirectory 
	 * @param @param directory
	 * @param @throws IOException
	 * @return void
	 * @user lt
	 * 2016年3月17日
	 * @throws
	 */
	public static void closeDirectory(Directory directory)
	{
		if (null != directory)
		{
			try
			{
				directory.close();
				directory = null;
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 
	 * 方法描述：是否可写
	 * @Title: isWritten 
	 * @param @param path
	 * @param @return
	 * @return boolean
	 * @user Administrator
	 * 2016年3月17日
	 * @throws
	 */
	public static boolean isWritten(String path)
	{
		String readTxt = FileUtils.read(path +"\\"+FILENAME);
		
		if(readTxt == null || "".equals(readTxt) || WRITTEN.equals(readTxt))
		{
			return true;
		}
		return false;
	}
	
	/**
	 * 
	 * 方法描述：是否可读
	 * @Title: isWritten 
	 * @param @param path
	 * @param @return
	 * @return boolean
	 * @user Administrator
	 * 2016年3月17日
	 * @throws
	 */
	public static boolean isRead(String path)
	{
		String readTxt = FileUtils.read(path +"\\"+FILENAME);
		
		if(readTxt != null && READ.equals(readTxt))
		{
			return true;
		}
		return false;
	}
	
}
